/*
 * Block.h
 *
 *  Created on: May 31, 2011
 *      Author: hongyang
 */

#ifndef BLOCK_H_
#define BLOCK_H_

//#include "Board.h"
#include "../smartgame/SgBlackWhite.h"
#include "../smartgame/SgPoint.h"
#include "../smartgame/SgPointSetUtil.h"
#include "../smartgame/SgArrayList.h"
#include "../smartgame/SgPointSet.h"
#include "../smartgame/SgDebug.h"
#include "Move.h"
#include "Util.h"

const int MAX_LIBERTIES = (SG_MAX_SIZE / 3) * 2 * SG_MAX_SIZE;

typedef SgArrayList<SgPoint, MAX_LIBERTIES> LibertyList;

typedef SgArrayList<SgPoint, SG_MAX_ONBOARD+1> PointList;

typedef LibertyList::Iterator LibertyIterator;

typedef PointList::Iterator StoneIterator;

/**
 * A block is a connected unit of stones in the same color.
 */
class Block {
public:
	Block();
	Block(const Block& b);
	bool operator==(const Block& b) const {
		return id == b.id;
	}
	virtual ~Block();
	void clear();
	void copy(const Block& b);
	void init(Move m);
	void appendLib(SgPoint p);
	void appendStone(SgPoint p);
	void removeLib(SgPoint p);
	void popStone();
	const PointList& getPoints() const;
	const SgPointSet& pointSet() const;
	const LibertyList& getLibs() const;
	int numPoints() const;
	int numLib() const;
	SgBlackWhite color() const;
	SgPoint getAnchor() const;
	void print() const;
	SgPoint getOldPt() const;
	void setDelete() {
		SG_ASSERT(!deleted);
		deleted = true;
	}
	bool isDeleted() const {
		return deleted;
	}
private:
	PointList points;
	SgPointSet set;

	LibertyList liberties;

	SgBlackWhite player;

	/**
	 * may be useless
	 */
	SgPoint anchor;
	int id;
	bool deleted;
	static int alloc_blocks;
};


inline void Block::init(Move m) {
	clear();
	deleted = false;
	player = m.Color();
	points.SetTo(m.Point());
	set.Include(m.Point());
	liberties.Clear();
	anchor = m.Point();
	id = alloc_blocks++;
}

inline void Block::appendLib(SgPoint p) {
	liberties.PushBack(p);
}

inline void Block::appendStone(SgPoint p) {
	points.PushBack(p);
	set.Include(p);
}

inline const PointList& Block::getPoints() const {
	return points;
}

inline const LibertyList& Block::getLibs() const {
	return liberties;
}

inline void Block::popStone() {
	SgPoint p = points.Last();
	points.PopBack();
	set.Exclude(p);
}

inline void Block::removeLib(SgPoint p) {
	liberties.Exclude(p);
}

inline SgBlackWhite Block::color() const {
	return player;
}

inline int Block::numLib() const {
	return liberties.Length();
}

inline SgPoint Block::getAnchor() const {
	return anchor;
}

inline int Block::numPoints() const {
	return points.Length();
}

inline const SgPointSet& Block::pointSet() const {
	return set;
}

inline void Block::print() const {
	SgDebug() << "block " <<  " id " << id << " addr " << this << " anchor " << SgWritePoint(anchor) << "points " << SgWritePointSet(set);
}

inline SgPoint Block::getOldPt() const {
	SgPoint p = points[0];
	if(p != anchor) return p;
	else return points[1];
}

#endif /* BLOCK_H_ */
